﻿using System;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Diagnostics;

namespace MyDesktopMicroBlog.Converter
{
    public class TextBlockContentConverter
    {
        public static readonly DependencyProperty TextProperty =
            DependencyProperty.RegisterAttached("Text", typeof(string), typeof(TextBlockContentConverter),
            new PropertyMetadata(null, OnTextChanged));

        private static readonly Regex RE_URL = new Regex(@"#\w+#|@\w+|http://\w*\.(\w+\.\w+|\w+)\S+", RegexOptions.IgnoreCase);

        public static string GetText(DependencyObject d) { return d.GetValue(TextProperty) as string; }
        public static void SetText(DependencyObject d, string value) { d.SetValue(TextProperty, value); }

        private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var txtBlock = d as TextBlock;
            if (txtBlock == null)
                return;
            //clear it's content first
            txtBlock.Inlines.Clear();

            //read its new value
            var newText = (string)e.NewValue;
            if (string.IsNullOrEmpty(newText))
            {
                return;
            }

            // Find all URLs using a regular expression            
            int last_pos = 0;
            foreach (Match match in RE_URL.Matches(newText))
            {
                // Copy raw string from the last position up to the match          
                if (match.Index != last_pos)
                {
                    var raw_text = newText.Substring(last_pos, match.Index - last_pos);
                    txtBlock.Inlines.Add(new Run(raw_text));
                }

                string url = match.Value;
                if (url.ToLower().StartsWith("#"))
                {
                    url = "http://t.sohu.com/ht/" + mBlogAPI.Utils.QueryStringUtils.UrlEncode(url.Substring(1, url.Length - 2));
                }
                else if (url.ToLower().StartsWith("@"))
                {
                    url = "http://t.sohu.com/n/" + url.Substring(1, url.Length - 1);
                }

                // Create a hyperlink for the match        
                var link = new Hyperlink(new Run(match.Value))
                {
                    CommandParameter = url
                };
                link.Click += OnUrlClick;
                txtBlock.Inlines.Add(link);

                // Update the last matched position         
                last_pos = match.Index + match.Length;
            }

            // Finally, copy the remainder of the string           
            if (last_pos < newText.Length)
                txtBlock.Inlines.Add(new Run(newText.Substring(last_pos)));
        }

        private static void OnUrlClick(object sender, RoutedEventArgs e)
        {
            var link = (Hyperlink)sender;
            Process.Start(link.CommandParameter.ToString());
        }
    }

    public class TextBlockContentConverterBak
    {
        public static readonly DependencyProperty TextProperty =
            DependencyProperty.RegisterAttached("Text", typeof(string), typeof(TextBlockContentConverter),
            new PropertyMetadata(null, OnTextChanged));

        public static string GetText(DependencyObject d) { return d.GetValue(TextProperty) as string; }
        public static void SetText(DependencyObject d, string value) { d.SetValue(TextProperty, value); }

        private static void OnTextChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            string text = args.NewValue as string;
            if (!string.IsNullOrEmpty(text))
            {
                TextBlock textblock = (TextBlock)obj;
                textblock.Inlines.Clear();
                textblock.Inlines.Add(" ");

                string[] words = Regex.Split(text, @"([ \(\)\{\}\[\]])");

                string possibleUserName = words[0].ToString();

                if ((possibleUserName.Length > 1) && (possibleUserName.Substring(1, 1) == "@"))
                {
                    textblock = FormatName(textblock, possibleUserName);
                    words.SetValue("", 0);
                }

                foreach (string word in words)
                {
                    // clickable hyperlinks
                    if (IsUrl(word))
                    {
                        try
                        {
                            Hyperlink link = new Hyperlink();
                            link.NavigateUri = new Uri(word);
                            link.Inlines.Add(word);
                            link.Click += new RoutedEventHandler(link_Click);
                            link.ToolTip = "Open link in the default browser";
                            textblock.Inlines.Add(link);
                        }
                        catch
                        {
                            //TODO:What are we catching here? Why? Log it?
                            textblock.Inlines.Add(word);
                        }
                    }
                    // clickable @name
                    else if (word.StartsWith("@"))
                    {
                        textblock = FormatName(textblock, word);

                    }

                    // clickable #hashtag
                    else if (word.StartsWith("#"))
                    {
                        string hashtag = String.Empty;
                        Match foundHashtag = Regex.Match(word, @"#(\w+)(?<suffix>.*)");
                        if (foundHashtag.Success)
                        {
                            hashtag = foundHashtag.Groups[1].Captures[0].Value;
                            Hyperlink tag = new Hyperlink();
                            tag.Inlines.Add(hashtag);

                            string hashtagUrl = "http://search.twitter.com/search?q=%23{0}";

                            // The main application has access to the Settings class, where a 
                            // user-defined hashtagUrl can be stored.  This hardcoded one that
                            // is used to set the NavigateUri is just a default behavior that
                            // will be used if the click event is not handled for some reason.

                            tag.NavigateUri = new Uri(String.Format(hashtagUrl, hashtag));
                            tag.ToolTip = "Show statuses that include this hashtag";
                            tag.Tag = hashtag;

                            tag.Click += new RoutedEventHandler(hashtag_Click);

                            textblock.Inlines.Add("#");
                            textblock.Inlines.Add(tag);
                            textblock.Inlines.Add(foundHashtag.Groups["suffix"].Captures[0].Value);
                        }
                    }
                    else
                    {
                        textblock.Inlines.Add(word);
                    }
                }

                textblock.Inlines.Add(" ");
            }
        }
        public static bool IsUrl(string word)
        {
            if (!Uri.IsWellFormedUriString(word, UriKind.Absolute))
                return false;

            Uri uri = new Uri(word);
            foreach (string acceptedScheme in new string[] { "http", "https", "ftp" })
                if (uri.Scheme == acceptedScheme)
                    return true;

            return false;
        }
        public static TextBlock FormatName(TextBlock textblock, string word)
        {
            string userName = String.Empty;
            string firstLetter = word.Substring(0, 1);

            Match foundUsername = Regex.Match(word, @"@(\w+)(?<suffix>.*)");

            if (foundUsername.Success)
            {
                userName = foundUsername.Groups[1].Captures[0].Value;
                Hyperlink name = new Hyperlink();
                name.Inlines.Add(userName);
                name.NavigateUri = new Uri("http://twitter.com/" + userName);
                name.ToolTip = "View @" + userName + "'s recent tweets";
                name.Tag = userName;

                name.Click += new RoutedEventHandler(name_Click);

                if (firstLetter != "@")
                    textblock.Inlines.Add(firstLetter);

                textblock.Inlines.Add("@");
                textblock.Inlines.Add(name);
                textblock.Inlines.Add(foundUsername.Groups["suffix"].Captures[0].Value);
            }
            return textblock;
        }

        #region Clickable #hashtag

        static void hashtag_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                // As a fallback (i.e., if the event is not handled), we launch the hyperlink's
                // URL in a web browser

                System.Diagnostics.Process.Start(((Hyperlink)sender).NavigateUri.ToString());

            }
            catch
            {
                //TODO: Log specific URL that caused error
                MessageBox.Show("There was a problem launching the specified URL.", "Error", MessageBoxButton.OK, MessageBoxImage.Exclamation);
            }
        }
        #endregion

        #region Clickable @name

        static void name_Click(object sender, RoutedEventArgs e)
        {
            // The event handler in the main application can handle the click event in a custom
            // fashion (i.e., show the tweets in Witty or launch a URL, etc).  That behavior is
            // not implemented here.
            try
            {
                // As a fallback (i.e., if the event is not handled), we launch the hyperlink's
                // URL in a web browser
                System.Diagnostics.Process.Start(((Hyperlink)sender).NavigateUri.ToString());
            }
            catch
            {
                //TODO: Log specific URL that caused error
                MessageBox.Show("There was a problem launching the specified URL.", "Error", MessageBoxButton.OK, MessageBoxImage.Exclamation);
            }
        }

        #endregion

        #region Regular Hyperlink Click

        static void link_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                System.Diagnostics.Process.Start(((Hyperlink)sender).NavigateUri.ToString());
            }
            catch
            {
                //TODO: Log specific URL that caused error
                MessageBox.Show("There was a problem launching the specified URL.", "Error", MessageBoxButton.OK, MessageBoxImage.Exclamation);
            }
        }
        #endregion
        private static void OnUrlClick(object sender, RoutedEventArgs e)
        {
            var link = (Hyperlink)sender;
            Process.Start(link.CommandParameter.ToString());
        }
    }
}
